import {
  makeCaptcha
} from '../../share/index'
import {
  verifyCollection,
  db
} from '../utils/config'
import { isPlainObject } from '../../share/utils'
import { VerifyCode } from './verify'
import { UniCaptcha } from '../base'

export class Captcha extends UniCaptcha {
  constructor () {
    super()
    this.DEVICEID2opts = {}
  }

  mergeConfig (options) {
    const sceneOptions = isPlainObject(this.pluginConfig.scene)
      ? this.pluginConfig.scene[options.scene]
      : options.scene

    return Object.assign(
      {},
      isPlainObject(sceneOptions) ? sceneOptions : this.pluginConfig,
      options
    )
  }

  /**
   *
   * @param {String} scene 使用场景，如：login pay register unbind等
   */
  async create (options = {}) {
    if (!options.scene) {
      throw new Error('scene验证码场景不可为空')
    }

    options = this.mergeConfig(options)
    let { scene, expiresDate, deviceId, clientIP, ...captchaOptions } = options

    deviceId = deviceId || __ctx__.DEVICEID
    clientIP = clientIP || __ctx__.CLIENTIP

    if (!deviceId) {
      throw new Error('deviceId不可为空')
    }

    const verifyCode = new VerifyCode()

    try {
      const { text, base64 } = makeCaptcha(captchaOptions)
      const setCodeRes = await verifyCode.setVerifyCode({
        clientIP,
        deviceId,
        code: text,
        expiresDate,
        scene
      })
      if (setCodeRes.code > 0) {
        return {
          ...setCodeRes,
          code: 10001
        }
      }

      this.DEVICEID2opts[deviceId] = options

      return {
        code: 0,
        msg: '验证码获取成功',
        captchaBase64: base64
      }
    } catch (error) {
      return {
        code: 10001,
        msg: `验证码生成失败：${error.message}`
      }
    }
  }

  async verify ({
    deviceId,
    captcha,
    scene
  }) {
    deviceId = deviceId || __ctx__.DEVICEID

    if (!deviceId) {
      throw new Error('deviceId不可为空')
    }

    if (!scene) {
      throw new Error('scene验证码场景不可为空')
    }

    const verifyCode = new VerifyCode()

    try {
      const verifyCodeRes = await verifyCode.verifyCode({
        deviceId,
        code: captcha,
        scene
      })
      if (verifyCodeRes.code > 0) {
        return verifyCodeRes
      }
      return {
        code: 0,
        msg: '验证码通过'
      }
    } catch (error) {
      return {
        code: 10002,
        msg: `验证码校验失败：${error.message}`
      }
    }
  }

  async refresh (options = {}) {
    let { scene, expiresDate, deviceId, ...captchaOptions } = options

    deviceId = deviceId || __ctx__.DEVICEID

    if (!deviceId) {
      throw new Error('deviceId不可为空')
    }

    if (!scene) {
      throw new Error('scene验证码场景不可为空')
    }
    const record = await verifyCollection.where(
      db.command.or([
        {
          device_uuid: deviceId,
          scene
        },
        {
          deviceId,
          scene
        }
      ])
    ).orderBy('created_date', 'desc').limit(1).get()

    if (record && record.data && record.data.length > 0) {
      const matched = record.data[0]
      // 状态改为已作废
      await verifyCollection.doc(matched._id).update({
        state: 2
      })

      // 如果传入生成配置，则使用此配置，否则使用缓存配置
      if (Object.keys(captchaOptions).length > 0) {
        // 更新缓存options
        this.DEVICEID2opts[deviceId] = Object.assign({}, this.DEVICEID2opts[deviceId], captchaOptions)
      }

      // 重新生成验证码
      let getCodeRes = {}
      try {
        getCodeRes = await this.create(Object.assign({}, this.DEVICEID2opts[deviceId], { deviceId, scene, expiresDate }))
      } catch (error) {
        return {
          code: 50403,
          msg: error.message
        }
      }

      if (getCodeRes.code > 0) {
        return {
          ...getCodeRes,
          code: 50403
        }
      }

      return {
        code: 0,
        msg: '验证码刷新成功',
        captchaBase64: getCodeRes.captchaBase64
      }
    } else {
      return {
        code: 10003,
        msg: `验证码刷新失败：无此设备在 ${scene} 场景信息，请重新获取`
      }
    }
  }
}
